package io.renren.modules.workmanagement.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.renren.common.exception.RRException;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.Query;
import io.renren.modules.sys.entity.SysUserEntity;
import io.renren.modules.sys.service.SysUserService;
import io.renren.modules.workmanagement.constans.UserConstans;
import io.renren.modules.workmanagement.dao.WorkDao;
import io.renren.modules.workmanagement.entity.*;
import io.renren.modules.workmanagement.enums.QuTypeEnums;
import io.renren.modules.workmanagement.enums.WorkFinishStatusEnums;
import io.renren.modules.workmanagement.enums.WorkStatusEnum;
import io.renren.modules.workmanagement.service.*;
import io.renren.modules.workmanagement.utils.PojoUtils;
import io.renren.modules.workmanagement.vo.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


@Service("workService")
public class WorkServiceImpl extends ServiceImpl<WorkDao, WorkEntity> implements WorkService {
    @Autowired
    private StudentService studentService;
    @Autowired
    private ClassService classService;
    @Autowired
    private ClassCourseService classCourseService;
    @Autowired
    private CourseService courseService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private QuestionBankService questionBankService;
    @Autowired
    private QuRepoService quRepoService;
    @Autowired
    private QuestionService questionService;
    @Autowired
    private QuestionAnswerService questionAnswerService;
    @Autowired
    private WorkAnswerService workAnswerService;
    @Autowired
    private WorkFinishStatusDetailService workFinishStatusDetailService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        String key = (String) params.get("key");
        SysUserEntity sysUserEntity = (SysUserEntity) params.get(UserConstans.USER_KEY);
        LambdaQueryWrapper<WorkEntity> wrapper = new LambdaQueryWrapper();
        Long userId = sysUserEntity.getUserId();
        //查询所在班级id
        StudentEntity student = studentService.getByUserId(userId);
        Long classId = student.getClassId();
        ClassVO classVO = classService.getClassById(classId);
        //查询班级课程
        List<ClassCourseEntity> classCourseList = classCourseService.getByClassId(classId);
        List<Long> searchTeachIds = null;
        if(StringUtils.isNotBlank(key)){
            List<CourseEntity> courseEntityList = courseService.likeByName(key);
            List<Long> courseIds = PojoUtils.streamMapList(courseEntityList, CourseEntity::getId);
            List<QuestionBankEntity> questionBankEntities = questionBankService.likeByName(key);
            List<SysUserEntity> userEntityList = sysUserService.likeByName(key);
            if(CollectionUtils.isNotEmpty(courseIds)){
                classCourseList = classCourseList.stream().filter(classCourse -> courseIds.contains(classCourse.getCourseId())).collect(Collectors.toList());
            }
            if(CollectionUtils.isNotEmpty(questionBankEntities)){
                List<Long> bankIds = PojoUtils.streamMapList(questionBankEntities, QuestionBankEntity::getId);
                wrapper.in(WorkEntity::getQuBankId, bankIds);
            }
            if(CollectionUtils.isNotEmpty(userEntityList)){
                searchTeachIds = PojoUtils.streamMapList(userEntityList, SysUserEntity::getUserId);
            }
        }
        Set<Long> teacherIds = PojoUtils.streamMapSet(classCourseList, ClassCourseEntity::getTeacherId);
        if(CollectionUtil.isNotEmpty(searchTeachIds)){
            List<Long> finalSearchTeachIds = searchTeachIds;
            teacherIds = teacherIds.stream().filter(teacherId -> finalSearchTeachIds.contains(teacherId)).collect(Collectors.toSet());
        }
        List<SysUserEntity> userEntityList = sysUserService.listByIds(teacherIds);
        Map<Long, SysUserEntity> sysUserEntityMap = PojoUtils.listToMap(userEntityList, SysUserEntity::getUserId, Function.identity());
        List<Long> classCourseIds = PojoUtils.streamMapList(classCourseList, ClassCourseEntity::getId);
        Set<Long> courseIds = PojoUtils.streamMapSet(classCourseList, ClassCourseEntity::getCourseId);
        List<CourseEntity> courseList = courseService.listByIds(courseIds);
        Map<Long, CourseEntity> courseEntityMap = PojoUtils.listToMap(courseList, CourseEntity::getId, Function.identity());
        Map<Long, ClassCourseEntity> courseClassMap = PojoUtils.listToMap(classCourseList, ClassCourseEntity::getId, Function.identity());
        params.remove(UserConstans.USER_KEY);
        if (CollectionUtil.isEmpty(classCourseIds)) {
            throw new RRException("该班级下还没有课程");
        }

        IPage<WorkEntity> page = this.page(
                new Query<WorkEntity>().getPage(params),
                wrapper.in(WorkEntity::getClassCourseId, classCourseIds)
        );
        List<WorkEntity> records = page.getRecords();
        if (CollectionUtil.isEmpty(records)) {
            return new PageUtils(page);
        }
        List<Long> workIds = PojoUtils.streamMapList(records, WorkEntity::getId);
        List<WorkFinishStatusDetailEntity> workFinishStatusDetailEntities = workFinishStatusDetailService.getByWorkIdsAndUserId(workIds, userId);
        Map<Long, List<WorkFinishStatusDetailEntity>> groupByWorkId = PojoUtils.listGroupByKey(workFinishStatusDetailEntities, WorkFinishStatusDetailEntity::getWorkId);
        Set<Long> quBankIds = PojoUtils.streamMapSet(records, WorkEntity::getQuBankId);
        List<QuestionBankEntity> bankEntityList = questionBankService.listByIds(quBankIds);
        Map<Long, QuestionBankEntity> questionBankEntityMap = PojoUtils.listToMap(bankEntityList, QuestionBankEntity::getId, Function.identity());

        IPage<MyWorkVO> convert = page.convert(workEntity -> {
            List<WorkFinishStatusDetailEntity> finished = groupByWorkId.get(workEntity.getId());
            QuestionBankEntity questionBank = questionBankEntityMap.get(workEntity.getQuBankId());
            ClassCourseEntity classCourseEntity = courseClassMap.get(workEntity.getClassCourseId());
            CourseEntity courseEntity = courseEntityMap.get(classCourseEntity.getCourseId());
            Long teacherId = classCourseEntity.getTeacherId();
            SysUserEntity teacher = sysUserEntityMap.get(teacherId);
            MyWorkVO myWorkVO = new MyWorkVO();
            BeanUtils.copyProperties(workEntity, myWorkVO);
            myWorkVO.setCourseId(courseEntity.getId());
            myWorkVO.setCourseName(courseEntity.getName());
            myWorkVO.setTeacherId(teacher.getUserId());
            myWorkVO.setTeacherName(teacher.getName());
            myWorkVO.setClassId(classVO.getId());
            myWorkVO.setClassName(classVO.getName());
            myWorkVO.setWorkName(questionBank.getTitle());
            myWorkVO.setStatus(getFinshStatus(workEntity.getStartTime(), workEntity.getEndTime()));
            myWorkVO.setFinshed(CollectionUtils.isNotEmpty(finished) ? 1 : 0);
            return myWorkVO;
        });
        return new PageUtils(convert);
    }

    @Override
    public List<WorkEntity> listByClassCourseIds(List<Long> classCourseIds) {
        return this.lambdaQuery().in(CollectionUtil.isNotEmpty(classCourseIds), WorkEntity::getClassCourseId, classCourseIds).list();
    }

    @Override
    public WorkDetailsVO getWorkDetails(Long workId, Long userId) {
        List<WorkAnswerEntity> workAnswers = workAnswerService.getByWorkIdAndUserId(workId, userId);
        List<Long> workAnswerQuIds = PojoUtils.streamMapList(workAnswers, WorkAnswerEntity::getQuId);
        WorkEntity work = this.getById(workId);
        Long quBankId = work.getQuBankId();
        List<QuRepoEntity> quRepoEntityList = quRepoService.listByQuBankId(quBankId);
        List<Long> quIds = PojoUtils.streamMapList(quRepoEntityList, QuRepoEntity::getQuId);
        List<QuestionEntity> questionEntities = questionService.listByIds(quIds);
        List<QuestionAnswerEntity> questionAnswerEntityList = questionAnswerService.ListByQuestionIds(quIds);
        Map<Long, List<QuestionAnswerEntity>> questionAnswerMap = PojoUtils.listGroupByKey(questionAnswerEntityList, QuestionAnswerEntity::getQuId);

        List<WorkDetailQuestionAnswerVO> collect = new ArrayList<>(questionEntities.size());
        for (QuestionEntity item : questionEntities) {
            Boolean answered = Optional.ofNullable(workAnswerQuIds)
                    .filter(CollectionUtil::isNotEmpty)
                    .map(list -> list.contains(item.getId()))
                    .orElse(false);
            List<QuestionAnswerEntity> answers = questionAnswerMap.get(item.getId());
            List<WorkDetailAnswerVO> workDetailAnswers = answers.stream().map(answer -> {
                WorkDetailAnswerVO workDetailAnswerVO = new WorkDetailAnswerVO();
                workDetailAnswerVO.setAnswerId(answer.getId());
                workDetailAnswerVO.setAnswer(answer.getContent());
                return workDetailAnswerVO;
            }).collect(Collectors.toList());
            WorkDetailQuestionAnswerVO workDetailQuestionAnswerVO = new WorkDetailQuestionAnswerVO();
            workDetailQuestionAnswerVO.setId(item.getId());
            workDetailQuestionAnswerVO.setQuestion(item.getContent());
            workDetailQuestionAnswerVO.setQuType(item.getQuType());
            workDetailQuestionAnswerVO.setAnswered(answered);
            workDetailQuestionAnswerVO.setAnswers(workDetailAnswers);
            collect.add(workDetailQuestionAnswerVO);
        }
        Map<Integer, List<WorkDetailQuestionAnswerVO>> integerListMap = PojoUtils.listGroupByKey(collect, WorkDetailQuestionAnswerVO::getQuType);
        Map<Integer, List<WorkDetailQuestionAnswerVO>> treeMap = new TreeMap<>(integerListMap);
        int sort = 0;
        for (Map.Entry<Integer, List<WorkDetailQuestionAnswerVO>> entry : treeMap.entrySet()) {
            List<WorkDetailQuestionAnswerVO> value = entry.getValue();
            for (WorkDetailQuestionAnswerVO workDetailQuestionAnswerVO : value) {
                workDetailQuestionAnswerVO.setSort(sort);
                sort++;
            }
        }
        WorkDetailsVO workDetailsVO = new WorkDetailsVO();
        workDetailsVO.setWorkId(workId);
        Map<Integer, List<WorkDetailQuestionAnswerVO>> groupByQuType = PojoUtils.listGroupByKey(collect, WorkDetailQuestionAnswerVO::getQuType);
        workDetailsVO.setRadioList(CollectionUtil.isNotEmpty(groupByQuType.get(QuTypeEnums.RADIO.getQuType())) ? groupByQuType.get(QuTypeEnums.RADIO.getQuType()) : Collections.EMPTY_LIST);
        workDetailsVO.setMultiList(CollectionUtil.isNotEmpty(groupByQuType.get(QuTypeEnums.CHECKBOX.getQuType())) ? groupByQuType.get(QuTypeEnums.CHECKBOX.getQuType()) : Collections.EMPTY_LIST);
        workDetailsVO.setJudgeList(CollectionUtil.isNotEmpty(groupByQuType.get(QuTypeEnums.JUDGE.getQuType())) ? groupByQuType.get(QuTypeEnums.JUDGE.getQuType()) : Collections.EMPTY_LIST);
        return workDetailsVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitWork(Long workId, Long userId) {
        WorkFinishStatusDetailEntity statusDetail = workFinishStatusDetailService.getByWorkIdAndUserId(workId, userId);
        //if(statusDetail != null && statusDetail.getStatus() == WorkFinishStatusEnums.FINISH.getCode()){
        //    throw new RRException("已经提交过了");
        //}
        //StudentEntity student = studentService.getByUserId(userId);
        WorkEntity work = this.getById(workId);
        if (isTimeOut(work.getStartTime(), work.getEndTime())) {
            throw new RRException("作业提交时间已经截止");
        }
        if (statusDetail == null) {
            statusDetail = new WorkFinishStatusDetailEntity();
        }
        statusDetail.setWorkId(workId);
        statusDetail.setStudentId(userId);
        statusDetail.setStatus(WorkFinishStatusEnums.FINISH.getCode());
        workFinishStatusDetailService.saveOrUpdate(statusDetail);

    }

    @Override
    public WorkResultVO getWorkResult(Long workId, Long userId) {
        //根据作业id查询作业
        WorkEntity work = this.getById(workId);
        //获取题库id
        Long quBankId = work.getQuBankId();
        //根据题库id查询题库
        QuestionBankEntity bank = questionBankService.getById(quBankId);
        //根据题库id查询该题库下的所有试题
        List<QuRepoEntity> quRepoEntityList = quRepoService.listByQuBankId(quBankId);
        //收集所有的问题id
        List<Long> quIds = PojoUtils.streamMapList(quRepoEntityList, QuRepoEntity::getQuId);
        //根据问题id查询所有问题
        List<QuestionEntity> questionEntities = questionService.listByIds(quIds);
        List<QuestionAnswerEntity> questionAnswerEntityList = questionAnswerService.ListByQuestionIds(quIds);
        Map<Long, List<QuestionAnswerEntity>> questionAnswerMap = PojoUtils.listGroupByKey(questionAnswerEntityList, QuestionAnswerEntity::getQuId);
        List<WorkAnswerEntity> workAnswerList = workAnswerService.getByWorkIdAndUserId(workId, userId);
        Map<Long, List<WorkAnswerEntity>> workAnswerGroupByWorkId = PojoUtils.listGroupByKey(workAnswerList, WorkAnswerEntity::getQuId);
        List<QuestionAnswerVO> collect = new ArrayList<>(questionEntities.size());
        for (QuestionEntity item : questionEntities) {
            List<QuestionAnswerEntity> questionAnawers = questionAnswerMap.get(item.getId());
            List<WorkAnswerEntity> workAnswerEntityList = workAnswerGroupByWorkId.get(item.getId());
            List<Long> trueAnswersIds = questionAnawers.stream().filter(quAnswer -> quAnswer.getIsRight() == 1).map(QuestionAnswerEntity::getId).collect(Collectors.toList());
            List<Long> myAnswersIds = PojoUtils.streamMapList(workAnswerEntityList, WorkAnswerEntity::getAnswer);
            QuestionAnswerVO questionAnswerVO = new QuestionAnswerVO();
            questionAnswerVO.setQuId(item.getId());
            questionAnswerVO.setQuType(item.getQuType());
            questionAnswerVO.setContent(item.getContent());
            questionAnswerVO.setAnswered(workAnswerEntityList != null && workAnswerEntityList.size() > 0);
            questionAnswerVO.setIsRight(CollectionUtils.isEqualCollection(trueAnswersIds, myAnswersIds));
            List<AnswerDetailVO> list = questionAnawers.stream().map(an -> {
                AnswerDetailVO answerDetailVO = new AnswerDetailVO();
                answerDetailVO.setId(an.getId());
                answerDetailVO.setContent(an.getContent());
                answerDetailVO.setChecked(myAnswersIds.contains(an.getId()));
                answerDetailVO.setIsRight(an.getIsRight());
                return answerDetailVO;
            }).collect(Collectors.toList());
            questionAnswerVO.setAnswerList(list);
            collect.add(questionAnswerVO);
        }
        Map<Integer, List<QuestionAnswerVO>> integerListMap = PojoUtils.listGroupByKey(collect, QuestionAnswerVO::getQuType);
        Map<Integer, List<QuestionAnswerVO>> treeMap = new TreeMap<>(integerListMap);
        int sort = 0;
        for (Map.Entry<Integer, List<QuestionAnswerVO>> entry : treeMap.entrySet()) {
            List<QuestionAnswerVO> value = entry.getValue();
            for (QuestionAnswerVO vo : value) {
                vo.setSort(sort);
                sort++;
            }
        }
        WorkResultVO workResultVO = new WorkResultVO();
        workResultVO.setWorkId(workId);
        workResultVO.setTitle(bank.getTitle());
        workResultVO.setQuList(collect);
        return workResultVO;
    }

    @Override
    public List<StudentWorkDetail> getStudentWorkDetailList(Long workId) {
        WorkEntity work = this.getById(workId);
        Long classCourseId = work.getClassCourseId();
        ClassCourseEntity classCourseEntity = classCourseService.getById(classCourseId);
        Long classId = classCourseEntity.getClassId();
        List<StudentEntity> students = studentService.getListByClassIds(Arrays.asList(classId));
        List<Long> studentIds = PojoUtils.streamMapList(students, StudentEntity::getUserId);
        List<WorkFinishStatusDetailEntity> workFinishStatusDetailList = workFinishStatusDetailService.getByWorkIdAndUserIds(workId, studentIds);
        Map<Long, WorkFinishStatusDetailEntity> map = PojoUtils.listToMap(workFinishStatusDetailList, WorkFinishStatusDetailEntity::getStudentId, Function.identity());
        List<SysUserEntity> userEntityList = sysUserService.listByIds(studentIds);

        List<QuRepoEntity> quRepoEntities = quRepoService.listByQuBankId(work.getQuBankId());
        List<Long> quIds = PojoUtils.streamMapList(quRepoEntities, QuRepoEntity::getQuId);
        List<QuestionEntity> questionEntities = questionService.listByIds(quIds);
        List<QuestionAnswerEntity> questionAnswerEntityList = questionAnswerService.ListByQuestionIds(quIds);
        List<WorkAnswerEntity> workAnswers = workAnswerService.getByQuIds(quIds);
        Map<Long, List<QuestionAnswerEntity>> quAnswerMap = PojoUtils.listGroupByKey(questionAnswerEntityList, QuestionAnswerEntity::getQuId);
        Map<Long, List<WorkAnswerEntity>> workAnswerGroupByStudnetIdMap = PojoUtils.listGroupByKey(workAnswers, WorkAnswerEntity::getStudentId);
        int totalQuestion = quRepoEntities.size();
        List<StudentWorkDetail> collect = userEntityList.stream().map(item -> {
            WorkFinishStatusDetailEntity statusDetail = map.get(item.getUserId());
            List<WorkAnswerEntity> workAnswerEntityList = workAnswerGroupByStudnetIdMap.get(item.getUserId());
            int unAnswer = 0;
            int trueCount = 0;
            int ErrCount = 0;
            if (CollectionUtil.isEmpty(workAnswerEntityList)) {
                unAnswer = totalQuestion;
            } else {
                for (QuestionEntity questionEntity : questionEntities) {
                    Map<Long, List<WorkAnswerEntity>> thisQuAnswerMap = PojoUtils.listGroupByKey(workAnswerEntityList, WorkAnswerEntity::getQuId);

                    Long quId = questionEntity.getId();
                    List<QuestionAnswerEntity> questionAnswerEntityList1 = quAnswerMap.get(quId);
                    List<WorkAnswerEntity> workAnswerEntityList1 = thisQuAnswerMap.get(quId);
                    if (CollectionUtils.isEmpty(workAnswerEntityList1)) {
                        unAnswer++;
                        continue;
                    }
                    List<Long> trueAnswerIds = questionAnswerEntityList1.stream().filter(quAnswer -> quAnswer.getIsRight().equals(1)).map(QuestionAnswerEntity::getId).collect(Collectors.toList());
                    List<Long> myAnswerIds = PojoUtils.streamMapList(workAnswerEntityList1, WorkAnswerEntity::getAnswer);
                    if (CollectionUtils.isEqualCollection(myAnswerIds, trueAnswerIds)) {
                        trueCount++;
                    } else {
                        ErrCount++;
                    }
                }

            }
            StudentWorkDetail studentVO = new StudentWorkDetail();
            studentVO.setId(item.getUserId());
            studentVO.setStuNo(Long.parseLong(item.getUsername()));
            studentVO.setStuName(item.getName());
            studentVO.setStatus(statusDetail == null ? 0 : statusDetail.getStatus());
            studentVO.setTrueCount(trueCount);
            studentVO.setErrCount(ErrCount);
            studentVO.setUnAnswerCount(unAnswer);
            return studentVO;
        }).collect(Collectors.toList());
        return collect;
    }

    //判断时间是否过期
    private boolean isTimeOut(Date startTime, Date endTime) {
        if (startTime == null || endTime == null) {
            return false;
        }
        Date now = new Date();
        if (now.before(startTime) || now.after(endTime)) {
            return true;
        }
        return false;
    }

    private Integer getFinshStatus(Date startTime, Date endTime) {
        //判断当前时间是否小于开始时间
        if (System.currentTimeMillis() < startTime.getTime()) {
            return WorkStatusEnum.NOT_START.getCode();
        }
        //判断当前时间是否在开始时间和结束时间之间
        if (startTime.getTime() <= System.currentTimeMillis() && endTime.getTime() >= System.currentTimeMillis()) {
            return WorkStatusEnum.IN_PROGRESS.getCode();
        }

        //判断当前时间是否在结束时间之后
        if (endTime.getTime() < System.currentTimeMillis()) {
            return WorkStatusEnum.ENDED.getCode();
        }
        return WorkStatusEnum.NOT_START.getCode();
    }
}
